from typing import Optional

from fastapi import APIRouter, HTTPException, Depends, Request, Response, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from loguru import logger
from pydantic import BaseModel, Field, EmailStr

from .common import ApiResponse
from .dependencies import get_current_user
from ..models.user import user_manager, User

router = APIRouter(prefix="/auth", tags=["Authentication"])
security = HTTPBearer(auto_error=False)


class LoginRequest(BaseModel):
    """用户登录请求模型"""
    username: str = Field(
        min_length=3,
        max_length=50,
        description="用户名",
        examples=["admin"]
    )
    password: str = Field(
        min_length=6,
        max_length=100,
        description="密码",
        examples=["123456"]
    )
    remember_me: bool = Field(
        default=False,
        description="记住登录状态，将延长会话有效期",
        examples=[False]
    )


class RegisterRequest(BaseModel):
    """用户注册请求模型"""
    username: str = Field(
        min_length=3,
        max_length=50,
        description="用户名（3-50字符）",
        examples=["newuser"]
    )
    password: str = Field(
        min_length=6,
        max_length=100,
        description="密码（至少6字符）",
        examples=["securepass123"]
    )
    confirm_password: str = Field(
        min_length=6,
        max_length=100,
        description="确认密码",
        examples=["securepass123"]
    )
    email: Optional[EmailStr] = Field(
        default=None,
        description="邮箱地址（可选）",
        examples=["user@example.com"]
    )
    full_name: Optional[str] = Field(
        default=None,
        max_length=100,
        description="真实姓名（可选）",
        examples=["张三"]
    )


class UserResponse(BaseModel):
    """用户信息响应模型"""
    username: str = Field(description="用户名", examples=["admin"])
    email: Optional[str] = Field(description="邮箱地址", examples=["admin@example.com"])
    full_name: Optional[str] = Field(description="真实姓名", examples=["管理员"])
    is_active: bool = Field(description="账户是否激活", examples=[True])
    is_superuser: bool = Field(description="是否为超级用户", examples=[False])
    created_at: Optional[str] = Field(description="账户创建时间", examples=["2024-01-01T00:00:00"])
    last_login: Optional[str] = Field(description="最后登录时间", examples=["2024-01-02T12:00:00"])
    avatar_url: Optional[str] = Field(description="头像URL", examples=[None])
    bio: Optional[str] = Field(description="个人简介", examples=[None])


class LoginResponse(BaseModel):
    """登录响应模型"""
    message: str = Field(description="响应消息", examples=["登录成功"])
    user: UserResponse = Field(description="用户信息")
    session_token: str = Field(description="会话令牌", examples=["abc123xyz"])
    expires_at: str = Field(description="令牌过期时间", examples=["2024-01-02T00:00:00"])


async def require_auth(current_user: Optional[User] = Depends(get_current_user)) -> User:
    """要求用户认证"""
    if not current_user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="未认证或会话已过期",
            headers={"WWW-Authenticate": "Bearer"},
        )
    return current_user


def get_client_ip(request: Request) -> str:
    """获取客户端IP地址"""
    forwarded = request.headers.get("X-Forwarded-For")
    if forwarded:
        return forwarded.split(",")[0].strip()
    return request.client.host


def get_user_agent(request: Request) -> str:
    """获取用户代理"""
    return request.headers.get("User-Agent", "Unknown")


# API 端点
@router.post("/login",
             response_model=LoginResponse,
             summary="用户登录",
             description="""
    ## 用户登录接口
    
    用户通过用户名和密码进行身份验证，成功后返回会话令牌。
    
    ### 请求参数
    - **username**: 用户名（3-50字符）
    - **password**: 密码（至少6字符）
    - **remember_me**: 是否记住登录状态（影响会话过期时间）
    
    ### 响应说明
    - 成功时返回用户信息和会话令牌
    - 会话令牌用于后续API调用的身份验证
    - 记住登录状态时会话有效期为7天，否则为1天
    
    ### 错误码
    - **401**: 用户名或密码错误
    - **403**: 用户账号已被禁用
    - **500**: 服务器内部错误
    """,
             responses={
                 200: {
                     "description": "登录成功",
                     "content": {
                         "application/json": {
                             "example": {
                                 "message": "登录成功",
                                 "user": {
                                     "username": "admin",
                                     "email": "admin@example.com",
                                     "full_name": "管理员",
                                     "is_active": True,
                                     "is_superuser": False,
                                     "created_at": "2024-01-01T00:00:00",
                                     "last_login": "2024-01-02T12:00:00",
                                     "avatar_url": None,
                                     "bio": None
                                 },
                                 "session_token": "abc123xyz",
                                 "expires_at": "2024-01-02T00:00:00"
                             }
                         }
                     }
                 },
                 401: {
                     "description": "认证失败",
                     "content": {
                         "application/json": {
                             "example": {"detail": "用户名或密码错误"}
                         }
                     }
                 },
                 403: {
                     "description": "账户被禁用",
                     "content": {
                         "application/json": {
                             "example": {"detail": "用户账号已被禁用"}
                         }
                     }
                 }
             }
             )
async def login(
    login_data: LoginRequest,
    request: Request,
    response: Response
):
    """
    用户登录接口
    
    - **username**: 用户名
    - **password**: 密码
    - **remember_me**: 是否记住登录状态（影响会话过期时间）
    """
    try:
        # 验证用户
        user = await user_manager.authenticate_user(
            login_data.username,
            login_data.password
        )

        if not user:
            logger.warning(f"登录失败: 用户名或密码错误 - {login_data.username}")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="用户名或密码错误"
            )

        if not user.is_active:
            logger.warning(f"登录失败: 用户已被禁用 - {login_data.username}")
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="用户账号已被禁用"
            )

        # 创建会话
        expires_hours = 168 if login_data.remember_me else 24  # 7天 或 1天
        user_session = await user_manager.create_session(
            username=user.username,
            expires_hours=expires_hours,
            user_agent=get_user_agent(request),
            ip_address=get_client_ip(request)
        )

        if not user_session:
            logger.error(f"创建用户会话失败 - {user.username}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="登录失败，请重试"
            )

        # 设置响应头（可选：设置 httpOnly cookie）
        response.headers["X-Session-Token"] = user_session.session_token

        logger.info(f"用户登录成功: {user.username} from {get_client_ip(request)}")

        return LoginResponse(
            message="登录成功",
            user=UserResponse(**user.to_dict()),
            session_token=user_session.session_token,
            expires_at=user_session.expires_at.isoformat()
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"登录过程中发生错误: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="服务器内部错误"
        )


@router.post("/register",
             response_model=ApiResponse,
             summary="用户注册",
             description="""
    ## 用户注册接口
    
    创建新的用户账户。用户名必须唯一，邮箱地址可选但如果提供也必须唯一。
    
    ### 请求参数
    - **username**: 用户名（3-50字符，必须唯一）
    - **password**: 密码（至少6字符）
    - **confirm_password**: 确认密码（必须与密码一致）
    - **email**: 邮箱地址（可选，如提供必须唯一）
    - **full_name**: 真实姓名（可选）
    
    ### 验证规则
    - 用户名长度3-50字符
    - 密码长度至少6字符
    - 两次输入密码必须一致
    - 邮箱格式必须有效
    
    ### 错误码
    - **400**: 请求参数错误
    - **409**: 用户名或邮箱已存在
    - **500**: 服务器内部错误
    """,
             responses={
                 200: {
                     "description": "注册成功",
                     "content": {
                         "application/json": {
                             "example": {
                                 "success": True,
                                 "message": "注册成功",
                                 "data": {"username": "newuser"}
                             }
                         }
                     }
                 },
                 400: {
                     "description": "请求参数错误",
                     "content": {
                         "application/json": {
                             "example": {"detail": "两次输入的密码不一致"}
                         }
                     }
                 },
                 409: {
                     "description": "用户已存在",
                     "content": {
                         "application/json": {
                             "example": {"detail": "用户名已存在"}
                         }
                     }
                 }
             }
             )
async def register(register_data: RegisterRequest, request: Request):
    """
    用户注册接口
    
    - **username**: 用户名（3-50字符）
    - **password**: 密码（至少6字符）
    - **confirm_password**: 确认密码
    - **email**: 邮箱地址（可选）
    - **full_name**: 真实姓名（可选）
    """
    try:
        # 验证密码确认
        if register_data.password != register_data.confirm_password:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="两次输入的密码不一致"
            )

        # 创建用户
        user = await user_manager.create_user(
            username=register_data.username,
            password=register_data.password,
            email=register_data.email,
            full_name=register_data.full_name,
            is_superuser=False
        )

        if not user:
            # 检查具体原因
            existing_user = await user_manager.get_user(register_data.username)
            if existing_user:
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail="用户名已存在"
                )
            else:
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail="邮箱已被使用"
                )

        logger.info(f"新用户注册成功: {user.username} from {get_client_ip(request)}")

        return ApiResponse(
            success=True,
            message="注册成功",
            data={"username": user.username}
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"注册过程中发生错误: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="服务器内部错误"
        )


@router.post("/logout",
             response_model=ApiResponse,
             summary="用户登出",
             description="""
    ## 用户登出接口
    
    终止当前用户会话，清除会话令牌。
    
    ### 认证要求
    - 需要有效的Bearer Token
    
    ### 响应说明
    - 成功时清除用户会话
    - 会话令牌将失效，后续请求需要重新登录
    
    ### 错误码
    - **401**: 未认证或会话已过期
    - **500**: 服务器内部错误
    """,
             responses={
                 200: {
                     "description": "登出成功",
                     "content": {
                         "application/json": {
                             "example": {
                                 "success": True,
                                 "message": "登出成功"
                             }
                         }
                     }
                 },
                 401: {
                     "description": "未认证",
                     "content": {
                         "application/json": {
                             "example": {"detail": "未认证或会话已过期"}
                         }
                     }
                 }
             }
             )
async def logout(
    current_user: User = Depends(require_auth),
    credentials: HTTPAuthorizationCredentials = Depends(security)
):
    """
    用户登出接口
    
    需要在请求头中提供有效的 Bearer Token
    """
    try:
        session_token = credentials.credentials
        success = await user_manager.invalidate_session(session_token)

        if success:
            logger.info(f"用户登出成功: {current_user.username}")
            return ApiResponse(
                success=True,
                message="登出成功"
            )
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="登出失败"
            )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"登出过程中发生错误: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="服务器内部错误"
        )


@router.get("/me",
            response_model=UserResponse,
            summary="获取当前用户信息",
            description="""
    ## 获取当前用户信息接口
    
    获取当前已认证用户的详细信息。
    
    ### 认证要求
    - 需要有效的Bearer Token
    
    ### 响应说明
    - 返回当前用户的完整信息
    - 包括用户名、邮箱、权限等信息
    
    ### 错误码
    - **401**: 未认证或会话已过期
    """,
            responses={
                200: {
                    "description": "获取用户信息成功",
                    "content": {
                        "application/json": {
                            "example": {
                                "username": "admin",
                                "email": "admin@example.com",
                                "full_name": "管理员",
                                "is_active": True,
                                "is_superuser": False,
                                "created_at": "2024-01-01T00:00:00",
                                "last_login": "2024-01-02T12:00:00",
                                "avatar_url": None,
                                "bio": None
                            }
                        }
                    }
                }
            }
            )
async def get_current_user_info(current_user: User = Depends(require_auth)):
    """
    获取当前登录用户的信息
    
    需要在请求头中提供有效的 Bearer Token
    """
    return UserResponse(**current_user.to_dict())


@router.get("/check",
            response_model=ApiResponse,
            summary="检查认证状态",
            description="""
    ## 检查认证状态接口
    
    检查当前会话是否有效，不需要强制认证。
    
    ### 认证要求
    - 可选的Bearer Token
    
    ### 响应说明
    - 如果提供了有效令牌，返回认证成功和用户信息
    - 如果没有提供令牌或令牌无效，返回未认证状态
    
    ### 返回数据
    - **authenticated**: 是否已认证
    - **user**: 用户信息（如果已认证）
    """,
            responses={
                200: {
                    "description": "状态检查完成",
                    "content": {
                        "application/json": {
                            "examples": {
                                "authenticated": {
                                    "summary": "已认证状态",
                                    "value": {
                                        "success": True,
                                        "message": "已认证",
                                        "data": {
                                            "authenticated": True,
                                            "user": {
                                                "username": "admin",
                                                "email": "admin@example.com"
                                            }
                                        }
                                    }
                                },
                                "not_authenticated": {
                                    "summary": "未认证状态",
                                    "value": {
                                        "success": True,
                                        "message": "未认证",
                                        "data": {
                                            "authenticated": False,
                                            "user": None
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            )
async def check_auth_status(current_user: Optional[User] = Depends(get_current_user)):
    """
    检查当前认证状态
    
    不需要强制认证，返回当前状态
    """
    if current_user:
        return ApiResponse(
            success=True,
            message="用户已认证",
            data={
                "authenticated": True,
                "username": current_user.username
            }
        )
    else:
        return ApiResponse(
            success=True,
            message="用户未认证",
            data={"authenticated": False}
        )


class ChangePasswordRequest(BaseModel):
    current_password: str = Field(min_length=6, description="当前密码")
    new_password: str = Field(min_length=6, description="新密码")


@router.post("/change-password", response_model=ApiResponse, summary="修改密码")
async def change_password(
    password_data: ChangePasswordRequest,
    current_user: User = Depends(require_auth)
):
    """
    修改用户密码
    
    需要提供当前密码进行验证
    """
    try:
        # 验证当前密码
        if not current_user.verify_password(password_data.current_password):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="当前密码错误"
            )

        # 更新密码（这里需要在UserManager中添加相应方法）
        # 为简化，这里省略实现
        logger.info(f"用户 {current_user.username} 修改密码成功")

        return ApiResponse(
            success=True,
            message="密码修改成功"
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"修改密码过程中发生错误: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="服务器内部错误"
        )
